import type {OnyxUpdate} from 'react-native-onyx';
import Onyx from 'react-native-onyx';
import {flushQueue, queueOnyxUpdates} from '@libs/actions/QueuedOnyxUpdates';
import type {OnyxKey} from '@src/ONYXKEYS';
import ONYXKEYS from '@src/ONYXKEYS';
import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';

const queuedOnyxUpdates: OnyxUpdate[] = [
    {key: ONYXKEYS.NVP_TRY_FOCUS_MODE, value: true, onyxMethod: 'merge'},
    {key: ONYXKEYS.PREFERRED_THEME, value: 'system', onyxMethod: 'merge'},
    {key: ONYXKEYS.NVP_PREFERRED_LOCALE, value: 'en', onyxMethod: 'merge'},
    {
        key: ONYXKEYS.SESSION,
        value: {
            accountID: 18748326,
            authToken: 'testToken',
            email: 'abcd+2342424224@gmail.com',
            encryptedAuthToken: 'testEncryptedAuthToken',
            loading: false,
        },
        onyxMethod: 'merge',
    },
    {key: ONYXKEYS.IS_LOADING_APP, value: false, onyxMethod: 'merge'},
    {
        key: ONYXKEYS.CREDENTIALS,
        value: {
            autoGeneratedLogin: '',
            autoGeneratedPassword: '',
            login: 'abcd+2342424224@gmail.com',
        },
        onyxMethod: 'merge',
    },
    {key: ONYXKEYS.IS_SIDEBAR_LOADED, value: true, onyxMethod: 'merge'},
    {key: `${ONYXKEYS.COLLECTION.REPORT}2175919089355165`, value: {reportID: 'reportID'}, onyxMethod: 'merge'},
    {
        key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}2175919089355165`,
        value: {
            // eslint-disable-next-line @typescript-eslint/naming-convention
            '4135522899867010163': {
                reportActionID: '4135522899867010163',
            },
        },
        onyxMethod: 'merge',
    },
];

jest.mock('@src/CONFIG', () => ({
    IS_TEST_ENV: false,
}));

function getOnyxUpdateValue<T>(key: string): T | undefined {
    return queuedOnyxUpdates.find((item) => item.key === key)?.value as T | undefined;
}

async function testOnyxKeyValue<T>(key: OnyxKey): Promise<void> {
    const expectedValue = getOnyxUpdateValue<T>(key);
    return new Promise<void>((resolve) => {
        const connection = Onyx.connect({
            key,
            waitForCollectionCallback: false,
            callback: (value) => {
                Onyx.disconnect(connection);

                expect(value).toEqual(expectedValue);
                resolve();
            },
        });
    });
}

describe('actions/QueuedOnyxUpdates', () => {
    beforeAll(() => {
        Onyx.init({
            keys: ONYXKEYS,
        });
    });

    beforeEach(() => {
        return Onyx.clear().then(waitForBatchedUpdates);
    });

    describe('flushQueue', () => {
        it('should filter queued updates when currentAccountID is undefined', async () => {
            await queueOnyxUpdates(queuedOnyxUpdates);
            await Onyx.multiSet({
                [ONYXKEYS.SESSION]: null,
            });

            await flushQueue();

            await testOnyxKeyValue(ONYXKEYS.NVP_TRY_FOCUS_MODE);
            await testOnyxKeyValue(ONYXKEYS.PREFERRED_THEME);
            await testOnyxKeyValue(ONYXKEYS.NVP_PREFERRED_LOCALE);
            await testOnyxKeyValue(ONYXKEYS.SESSION);
            await testOnyxKeyValue(ONYXKEYS.IS_LOADING_APP);
            await testOnyxKeyValue(ONYXKEYS.CREDENTIALS);
            await testOnyxKeyValue(ONYXKEYS.IS_SIDEBAR_LOADED);

            await new Promise<void>((resolve) => {
                const connection = Onyx.connect({
                    key: `${ONYXKEYS.COLLECTION.REPORT}2175919089355165`,
                    waitForCollectionCallback: false,
                    callback: (report) => {
                        Onyx.disconnect(connection);
                        expect(report).toBeUndefined();

                        resolve();
                    },
                });
            });

            await new Promise<void>((resolve) => {
                const connection = Onyx.connect({
                    key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}2175919089355165`,
                    waitForCollectionCallback: false,
                    callback: (report) => {
                        Onyx.disconnect(connection);
                        expect(report).toBeUndefined();

                        resolve();
                    },
                });
            });
        });

        it('should not filter updates if currentAccountID is defined', async () => {
            await queueOnyxUpdates(queuedOnyxUpdates);
            await Onyx.multiSet({
                [ONYXKEYS.SESSION]: {
                    accountID: 1,
                },
            });

            await flushQueue();

            await testOnyxKeyValue(ONYXKEYS.NVP_TRY_FOCUS_MODE);
            await testOnyxKeyValue(ONYXKEYS.PREFERRED_THEME);
            await testOnyxKeyValue(ONYXKEYS.NVP_PREFERRED_LOCALE);
            await testOnyxKeyValue(ONYXKEYS.SESSION);
            await testOnyxKeyValue(ONYXKEYS.IS_LOADING_APP);
            await testOnyxKeyValue(ONYXKEYS.CREDENTIALS);
            await testOnyxKeyValue(ONYXKEYS.IS_SIDEBAR_LOADED);

            await new Promise<void>((resolve) => {
                const connection = Onyx.connect({
                    key: `${ONYXKEYS.COLLECTION.REPORT}2175919089355165`,
                    waitForCollectionCallback: false,
                    callback: (report) => {
                        Onyx.disconnect(connection);
                        expect(report).toEqual(getOnyxUpdateValue(`${ONYXKEYS.COLLECTION.REPORT}2175919089355165`));

                        resolve();
                    },
                });
            });

            await new Promise<void>((resolve) => {
                const connection = Onyx.connect({
                    key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}2175919089355165`,
                    waitForCollectionCallback: false,
                    callback: (reportActions) => {
                        Onyx.disconnect(connection);
                        expect(reportActions).toEqual(getOnyxUpdateValue(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}2175919089355165`));

                        resolve();
                    },
                });
            });
        });
    });
});
